﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using HYCodeBase.Algorithm.LRUCache;

namespace HYCodeBase.StringUtility.FuzzySearchSuite
{
	public class FuzzySearchManger
	{
		public FuzzySearchManger(List<ISearchItem> inputItems, bool ifUseWhiteSplite = true, bool ifNeedAllTarget = true, int limitCacheCount = 50)
		{
			this.m_nLimitCacheCount = limitCacheCount;
			this.m_bifUseWhiteSplite = ifUseWhiteSplite;
			this.m_bifNeedAllTarget = ifNeedAllTarget;
			this.m_cache = new LRUCacheManger<string, List<ISearchItem>>(this.m_nLimitCacheCount);
			foreach (ISearchItem inputItem in inputItems)
			{
				this.TryRegistOneItem(inputItem, false);
			}
		}

		public List<ISearchItem> Search(string input)
		{
			List<ISearchItem> list = new List<ISearchItem>();
			string text;
			string[] searchKey = FuzzySearchManger.GetSearchKey(input, this.m_bifUseWhiteSplite, out text);
			Dictionary<string, List<ISearchItem>> useSearchSource = this.m_dicSearchSource;
			List<List<ISearchItem>> list2 = new List<List<ISearchItem>>();
			if (searchKey == null)
			{
				return list;
			}
			if (this.IfCanUseLastCache(text))
			{
				useSearchSource = this.m_LastSearchcache.Value;
			}
			foreach (string text2 in searchKey)
			{
				this.AddSearchResultToCache(text2, useSearchSource);
				list2.Add(this.m_cache.Get(text2));
			}
			this.PrepareSearchedValue(list, list2);
			list = list.Distinct<ISearchItem>().ToList<ISearchItem>();
			Dictionary<string, List<ISearchItem>> value = (from k in list
			group k by FuzzySearchManger.AdjustString(k.ItemName)).ToDictionary((IGrouping<string, ISearchItem> k) => k.Key, (IGrouping<string, ISearchItem> k) => k.ToList<ISearchItem>());
			this.m_LastSearchcache = new KeyValuePair<string, Dictionary<string, List<ISearchItem>>>(text, value);
			return list;
		}

		private bool IfCanUseLastCache(string realUseString)
		{
			return !string.IsNullOrWhiteSpace(this.m_LastSearchcache.Key) && realUseString.Contains(this.m_LastSearchcache.Key);
		}

		public bool TryRegistOneItem(ISearchItem inputItem)
		{
			return this.TryRegistOneItem(inputItem, true);
		}

		private void AddSearchResultToCache(string oneKeyValue, Dictionary<string, List<ISearchItem>> useSearchSource)
		{
			if (!this.m_cache.IfContainsKey(oneKeyValue))
			{
				List<ISearchItem> list = new List<ISearchItem>();
				Regex regex = new Regex(oneKeyValue);
				foreach (KeyValuePair<string, List<ISearchItem>> keyValuePair in useSearchSource)
				{
					if (regex.IsMatch(keyValuePair.Key))
					{
						list.AddRange(keyValuePair.Value);
					}
				}
				list = list.Distinct<ISearchItem>().ToList<ISearchItem>();
				this.m_cache.Set(oneKeyValue, list);
			}
		}

		private void PrepareSearchedValue(List<ISearchItem> returnValue, List<List<ISearchItem>> searchedValue)
		{
			if (searchedValue.Count == 1)
			{
				returnValue.AddRange(searchedValue[0]);
				return;
			}
			if (searchedValue.Count >= 1)
			{
				if (this.m_bifNeedAllTarget)
				{
					List<ISearchItem> list = searchedValue[0];
					for (int i = 1; i < searchedValue.Count; i++)
					{
						list = list.Join(searchedValue[i], (ISearchItem k) => k, (ISearchItem k) => k, (ISearchItem k, ISearchItem z) => k).ToList<ISearchItem>();
					}
					returnValue.AddRange(list);
					return;
				}
				foreach (List<ISearchItem> collection in searchedValue)
				{
					returnValue.AddRange(collection);
				}
			}
		}

		private bool TryRegistOneItem(ISearchItem inputItem, bool ifAdjustCache)
		{
			if (inputItem == null || string.IsNullOrWhiteSpace(inputItem.ItemName))
			{
				return false;
			}
			string text = FuzzySearchManger.AdjustString(inputItem.ItemName);
			if (!this.m_dicSearchSource.ContainsKey(text))
			{
				this.m_dicSearchSource.Add(text, new List<ISearchItem>());
			}
			if (!this.m_dicSearchSource[text].Contains(inputItem))
			{
				this.m_dicSearchSource[text].Add(inputItem);
				if (this.IfCanUseLastCache(text))
				{
					if (!this.m_LastSearchcache.Value.ContainsKey(text))
					{
						this.m_LastSearchcache.Value.Add(text, new List<ISearchItem>());
					}
					this.m_LastSearchcache.Value[text].Add(inputItem);
				}
				if (ifAdjustCache)
				{
					foreach (KeyValuePair<string, List<ISearchItem>> keyValuePair in this.m_cache)
					{
						if (new Regex(keyValuePair.Key).IsMatch(text))
						{
							keyValuePair.Value.Add(inputItem);
						}
					}
				}
				return true;
			}
			return false;
		}

		private static string AdjustString(string inputString)
		{
			string input = inputString.Trim();
			return FuzzySearchManger.m_useWhiteRegex.Replace(input, " ");
		}

		private static string[] GetSearchKey(string inputString, bool ifUseWhiteSplite, out string realUseString)
		{
			realUseString = null;
			if (string.IsNullOrWhiteSpace(inputString))
			{
				return null;
			}
			realUseString = FuzzySearchManger.AdjustString(inputString);
			if (ifUseWhiteSplite)
			{
				return realUseString.Split(new char[]
				{
					" "[0]
				});
			}
			return new string[]
			{
				realUseString
			};
		}

		private const string m_strUseWhiteRegex = "\\s";

		private const string m_strUseWhite = " ";

		private static Regex m_useWhiteRegex = new Regex("\\s+");

		private Dictionary<string, List<ISearchItem>> m_dicSearchSource = new Dictionary<string, List<ISearchItem>>();

		private LRUCacheManger<string, List<ISearchItem>> m_cache;

		private KeyValuePair<string, Dictionary<string, List<ISearchItem>>> m_LastSearchcache;

		private bool m_bifUseWhiteSplite = true;

		private bool m_bifNeedAllTarget = true;

		private int m_nLimitCacheCount = 50;
	}
}
